今天要學習的模式我覺得很有趣,學完以後很常拿它用來做 undo、redo 的功能,因為它的功能就是用來保存和恢復物件的狀態的,現在就來認識一下吧!
現在有個文字編輯器,在執行任何操作之前,此編輯器就會記錄所有物件的狀態並且儲存到一個地方去,而當用戶想要恢復上一個狀態的時候,編輯器就會從歷史紀錄中拿到最近一筆的物件快照來恢復所有物件的狀態。
但如果要產生這些物件快照的話,就會需要取的物件的所有屬性才能夠複製到儲存的地方去,但是大多數的物件不會開放所有屬性給其它人存取,有些重要的資訊會存成私有屬性,這可能就會造成物件快照不完全。
而備忘錄模式會將創建物件快照的方法封裝到實際所有者(Originator)本身,因此不是其它物件從外部複製編輯器的狀態,是編輯器本身可以自己創建快照,如此就沒有公有、私有屬性的存取問題了。
這些快照會儲存在Memento類別中,再由Caretaker類別統一做管理,但不能修改Memento中的狀態,若是想要恢復上一個狀態的話,Originator可以存取Memento中的所有屬性來恢復。
import java.util.LinkedList;
class Caretaker {
private Originator originator;
private LinkedList<Memento> history = new LinkedList<Memento>();
public Caretaker(Originator originator) {
this.originator = originator;
}
public void saveMemento() {
history.push(originator.save());
}
public void undo() {
originator.restore(history.pop());
}
}
class Memento {
private State state;
public Memento(State state) {
this.state = state;
}
public State getState() {
return state;
}
}
class Originator {
private State state;
public Memento saveToMemento() {
return new Memento(state);
}
public void restore(Memento m) {
this.state = m.getState();
}
}
看完以後是不是也覺得Memento很適合拿來做上一步、下一步的功能呢!它可以不違反封裝的情況下生成物件快照,而且這些快照會讓Caretaker來管理,作為Originator狀態的歷史紀錄,使用者有需要的時候就可以拿來做恢復的動作。不過使用者過於頻繁的創建Memento的話,那系統可能就會消耗許多記憶體,這點可能要稍稍留意。
除此之外,也歡迎大家走走逛逛關於我們團隊夥伴的文章
juck30808 - Python - 數位行銷分析與 Youtube API 教學
SiQing47 - 前端?後端?你早晚都要全端的,何不從現在開始?